package com.lagou.sqlsession.impl;



import com.lagou.executor.Executor;
import com.lagou.executor.SimpleExecutor;
import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;
import com.lagou.sqlsession.SqlSession;

import java.lang.reflect.*;
import java.util.List;


/**
 * @Description:连接类
 * @author liujunling
 * @date 2020/3/31
 */
public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <T> List<T> selectList(String statementId, Object... params) throws Exception {
        Executor executor = new SimpleExecutor(configuration);
        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
        List<T> list = executor.query(mappedStatement,params);
        return list;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
        List<T> list = selectList(statementId, params);
        if (list.size()!=1){
            throw new RuntimeException("no data or not only one!");
        }
        return list.get(0);
    }

    private int delete( String statementId, Object... args) throws Exception  {
        return update(statementId,args);
    }

    private int insert(String statementId, Object... args) throws Exception  {
        return update(statementId,args);
    }

    private int update( String statementId, Object... args) throws Exception {
        Executor executor = new SimpleExecutor(configuration);
        MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
        return executor.update(mappedStatement,args);
    }


    @Override
    @SuppressWarnings("unchecked")
    public <E> E getMapper(Class<E> mapperInterface) throws Exception {
        InvocationHandler invocationHandler = new IPersistenceInvocationHandler(mapperInterface,configuration);
        Object o = Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, invocationHandler);
        return (E) o;
    }

    private class IPersistenceInvocationHandler implements InvocationHandler {
        private Class<?> proxyInterface;
        private Configuration configuration;

        public IPersistenceInvocationHandler(Class<?> proxyInterface, Configuration configuration) {
            this.proxyInterface = proxyInterface;
            this.configuration = configuration;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //statementId 接口全类名.方法名
            String interfaceName = proxyInterface.getName();
            String methodName = method.getName();
            String statementId = interfaceName+"."+methodName;
            MappedStatement mappedStatement = configuration.getMappedStatements().get(statementId);
            //根据返回值选择运行的方法
            Object result = null;
            Type returnType = method.getGenericReturnType();
            switch (mappedStatement.getMethodType()){
                case SELECT:
                    result  = proxySelect(returnType,statementId,args);
                    break;
                case INSERT:
                    result  = insert(statementId,args);
                    break;
                case UPDATE:
                    result  = update(statementId,args);
                    break;
                case DELETE:
                    result  = delete(statementId,args);
                    break;
                default:
                    break;
            }

            return result;
        }

        private Object proxySelect(Type  returnType,String statementId, Object... args) throws Exception {
            if (returnType instanceof ParameterizedType){
                //返回值包含泛型
                return selectList(statementId, args);
            }
            return selectOne(statementId, args);
        }
    }
}
